# -*- coding: utf-8 -*-
#
#  Copyright (C) 2012 by Ihor E. Novikov
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU Affero General Public License
#  as published by the Free Software Foundation, either version 3
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU Affero General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.

import struct
from colorsys import yiq_to_rgb, hls_to_rgb, hsv_to_rgb

from uc2 import uc2const, cms
from uc2.utils import double2py_float, word2py_int, long2py_float
from uc2.formats.cdr.cdr_const import cdrunit_to_pt, \
    CDR_COLOR_CMYK, CDR_COLOR_BGR, CDR_COLOR_CMY, CDR_COLOR_CMYK255, \
    CDR_COLOR_GRAY, CDR_COLOR_LAB, CDR_COLOR_REGISTRATION, CDR_COLOR_CMYK2, \
    CDR_COLOR_HSB, CDR_COLOR_HLS, CDR_COLOR_YIQ, CDR_COLOR_LAB2, CDR_CS_MATSH


def parse_matrix(data):
    """
    Parses CDR affine transformation matrix and
    returns matrix as a list.
    """
    m11 = double2py_float(data[0:8])
    m12 = double2py_float(data[8:16])
    dx = double2py_float(data[16:24]) * cdrunit_to_pt
    m21 = double2py_float(data[24:32])
    m22 = double2py_float(data[32:40])
    dy = double2py_float(data[40:48]) * cdrunit_to_pt
    return [m11, m21, m12, m22, dx, dy]


def parse_cmyk(data):
    """
    Parses CMYK color bytes and	returns fill style list.
    """
    c = ord(data[0]) / 100.0
    m = ord(data[1]) / 100.0
    y = ord(data[2]) / 100.0
    k = ord(data[3]) / 100.0
    return [uc2const.COLOR_CMYK, [c, m, y, k], 1.0, '']


def parse_cmyk255(data):
    """
    Parses CMYK255 color bytes and returns fill style list.
    """
    c = ord(data[0]) / 255.0
    m = ord(data[1]) / 255.0
    y = ord(data[2]) / 255.0
    k = ord(data[3]) / 255.0
    return [uc2const.COLOR_CMYK, [c, m, y, k], 1.0, '']


def parse_cmy(data):
    """
    Parses CMY color bytes and returns fill style list.
    """
    c = ord(data[0]) / 255.0
    m = ord(data[1]) / 255.0
    y = ord(data[2]) / 255.0
    k = 0.0
    return [uc2const.COLOR_CMYK, [c, m, y, k], 1.0, '']


def parse_bgr(data):
    """
    Parses BGR color bytes and returns fill style list.
    """
    b = ord(data[0]) / 255.0
    g = ord(data[1]) / 255.0
    r = ord(data[2]) / 255.0
    return [uc2const.COLOR_RGB, [r, g, b], 1.0, '']


def parse_lab(data):
    """
    Parses Lab color bytes and returns fill style list.
    """
    l = ord(data[0]) / 255.0
    a = ord(data[1]) / 255.0
    b = ord(data[2]) / 255.0
    return [uc2const.COLOR_LAB, [l, a, b], 1.0, '']


def parse_lab2(data):
    """
    Parses Lab color bytes and returns fill style list.
    """
    l = ord(data[0]) / 255.0
    a = ord(data[1]) / 255.0
    b = ord(data[2]) / 255.0
    return [uc2const.COLOR_LAB, [l, a, b], 1.0, '']


def parse_grayscale(data):
    """
    Parses Grayscale color byte and returns fill style list.
    """
    l = ord(data[0]) / 255.0
    return [uc2const.COLOR_GRAY, [l, ], 1.0, '']


def parse_hsb(data):
    """
    Parses HSB/HSV color bytes and returns fill style list.
    """
    h = word2py_int(data[0:2]) / 360.0
    s = ord(data[2]) / 255.0
    v = ord(data[3]) / 255.0
    r, g, b = hsv_to_rgb(h, s, v)
    return [uc2const.COLOR_RGB, [r, g, b], 1.0, '']


def parse_hls(data):
    """
    Parses HLS color bytes and returns fill style list.
    """
    h = word2py_int(data[0:2]) / 360.0
    l = ord(data[2]) / 255.0
    s = ord(data[3]) / 255.0
    r, g, b = hls_to_rgb(h, l, s)
    return [uc2const.COLOR_RGB, [r, g, b], 1.0, '']


def parse_yiq(data):
    """
    Parses YIQ color bytes and returns fill style list.
    """
    y = ord(data[0]) / 255.0
    i = 2.0 * ord(data[1]) / 255.0 - 1.0
    q = 2.0 * ord(data[2]) / 255.0 - 1.0
    r, g, b = yiq_to_rgb(y, i, q)
    return [uc2const.COLOR_RGB, [r, g, b], 1.0, '']


def parse_reg_color(data=''):
    """
    Returns Registration color fill style list.
    """
    return [uc2const.COLOR_SPOT,
            [[0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]],
            1.0, 'Registration color']


def parse_cdr_color(colorspace, color_bytes):
    """
    Parses color type and returns according color value.
    """
    if colorspace == CDR_COLOR_CMYK:
        return parse_cmyk(color_bytes)
    elif colorspace in (CDR_COLOR_CMYK255, CDR_COLOR_CMYK2):
        return parse_cmyk255(color_bytes)
    elif colorspace == CDR_COLOR_CMY:
        return parse_cmy(color_bytes[0:3])
    elif colorspace == CDR_COLOR_BGR:
        return parse_bgr(color_bytes[0:3])
    elif colorspace == CDR_COLOR_GRAY:
        return parse_grayscale(color_bytes[0])
    elif colorspace == CDR_COLOR_LAB:
        return parse_lab(color_bytes[0:3])
    elif colorspace == CDR_COLOR_LAB2:
        return parse_lab2(color_bytes[0:3])
    elif colorspace == CDR_COLOR_HSB:
        return parse_hsb(color_bytes)
    elif colorspace == CDR_COLOR_HLS:
        return parse_hls(color_bytes)
    elif colorspace == CDR_COLOR_YIQ:
        return parse_yiq(color_bytes[0:3])
    elif colorspace == CDR_COLOR_REGISTRATION:
        return parse_reg_color()
    return []


def parse_cdr_spot_color(cs, clrbytes, cs2, clrbytes2):
    spot = uc2const.COLOR_SPOT
    rgb = uc2const.COLOR_RGB
    cmyk = uc2const.COLOR_CMYK
    clr = parse_cdr_color(cs, clrbytes)
    clr2 = parse_cdr_color(cs2, clrbytes2)
    if not clr and clr2: return clr2
    if not clr2: return clr
    if clr[0] == clr2[0]:
        if clr[0] == rgb:
            return [spot, [clr[1], []], 1.0, '']
        elif clr[0] == cmyk:
            return [spot, [[], clr[1]], 1.0, '']
        else:
            return clr
    elif clr[0] in (rgb, cmyk) and clr2[0] in (rgb, cmyk):
        if clr[0] == rgb:
            return [spot, [clr[1], clr2[1]], 1.0, '']
        else:
            return [spot, [clr2[1], clr[1]], 1.0, '']
    elif clr[0] in (rgb, cmyk):
        return clr
    elif clr2[0] in (rgb, cmyk):
        return clr2
    else:
        return clr


def parse_size_value(data):
    """
    Convert 4-bytes string to value in points.
    """
    return long2py_float(data) * cdrunit_to_pt


def get_cdr_color(color):
    """
    Converts color list to CDR colorspace and color valbytes
    """
    cs = CDR_CS_MATSH[uc2const.COLOR_RGB]
    valbytes = '\x05\x05\x00\x00\x00\x00'
    if not color[0] == uc2const.COLOR_SPOT:
        cs = CDR_CS_MATSH[color[0]]
        if color[0] == uc2const.COLOR_RGB:
            r, g, b = cms.val_255(color[1])
            valbytes += struct.pack('<3B', b, g, r) + '\x00'
        elif color[0] == uc2const.COLOR_CMYK:
            valbytes += struct.pack('<4B', *cms.val_100(color[1]))
        elif color[0] == uc2const.COLOR_GRAY:
            valbytes += struct.pack('<B', *cms.val_255(color[1]))
            valbytes += '\xeb\x54\x01'
        if color[0] == uc2const.COLOR_LAB:
            valbytes = '\x0d\x00\x00\x00\x00\x00'
            valbytes += struct.pack('<3B', *cms.val_255(color[1])) + '\xcc'
    else:
        if color[1][1]:
            cs = CDR_CS_MATSH[uc2const.COLOR_CMYK]
            valbytes += struct.pack('<4B', *cms.val_100(color[1]))
        else:
            r, g, b = cms.val_255(color[1][0])
            valbytes += struct.pack('<3B', b, g, r) + '\x00'
    return cs, valbytes
